package pers.cfeng.server.dataManage.logger;

import pers.cfeng.common.DatabaseException;
import pers.cfeng.common.ErrorCode;
import pers.cfeng.server.utils.ByteBufferParser;
import pers.cfeng.server.utils.FaultHandler;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * 日志文件的操作，就是操作.log文件
 * 日志文件和每条日志都需要进行校验
 * [TCheckSum][Log1][log2]......BadTail； TCheckSum是4字节Int，表示校验和
 * 每一条日志
 * [Size][CheckSum][data]  size 为4字节的Int表示data长度
 */

public interface Logger {

    void log(byte[] data);

    void truncate(long x) throws Exception;

    //迭代器模式设计
    byte[] next();

    void rewind();

    void close();

    //日志文件的创建和打开
    static Logger create(String path) {
        File file = new File(path + LoggerConstant.LOG_SUFFIX);
        try {
            if(!file.createNewFile()) {
                FaultHandler.forcedStop(new DatabaseException(ErrorCode.FILE_EXISTS));
            }
        } catch (IOException e) {
            FaultHandler.forcedStop(e);
        }
        if(!file.canRead() || !file.canWrite()) {
            FaultHandler.forcedStop(new DatabaseException(ErrorCode.FILE_CANNOT_READ_OR_WRITE));
        }
        RandomAccessFile raf = null;
        FileChannel fileChannel = null;
        try {
            raf = new RandomAccessFile(file, "rw");
            fileChannel = raf.getChannel();
        } catch (Exception e) {
            FaultHandler.forcedStop(e);
        }
        //初始化的时候校验和为0
        ByteBuffer buffer = ByteBuffer.wrap(ByteBufferParser.int2Byte(0));
        try {
            fileChannel.position(0);
            fileChannel.write(buffer);
            fileChannel.force(false);
        } catch (Exception e) {
            FaultHandler.forcedStop(e);
        }
        //新建文件的时候log整个的校验和为0
        return new LoggerImpl(raf, fileChannel, 0);
    }

    static Logger open(String path) {
        File file = new File(path + LoggerConstant.LOG_SUFFIX);
        if(!file.exists()) {
            FaultHandler.forcedStop(new DatabaseException(ErrorCode.FILE_EXISTS));
        }

        if(!file.canRead() || !file.canWrite()) {
            FaultHandler.forcedStop(new DatabaseException(ErrorCode.FILE_CANNOT_READ_OR_WRITE));
        }
        RandomAccessFile raf = null;
        FileChannel fileChannel = null;
        try {
            raf = new RandomAccessFile(file, "rw");
            fileChannel = raf.getChannel();
        } catch (Exception e) {
            FaultHandler.forcedStop(e);
        }
        LoggerImpl logger =  new LoggerImpl(raf, fileChannel);
        logger.init();
        return logger;
    }

}
